package com.zhixiang.xaec.service.bpmndemo.impl;


import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import javax.annotation.Resource;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.zhixiang.core.command.QueryFilter;
import com.zhixiang.xaec.entity.bpmndemo.WorkflowConfig;
import com.zhixiang.xaec.service.bpmndemo.WorkflowConfigService;
import com.zhixiang.xaec.service.bpmndemo.WorkflowService;


/**
 * @author gao
 * @since 2017年1月5日
 */
@Service
public class WorkflowServiceImpl implements WorkflowService
{
    @Resource
    private RepositoryService repositoryService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private FormService formService;

    @Resource
    private HistoryService historyService;

    @Autowired
    private WorkflowConfigService workflowConfigService;

    /** 部署流程定义 */
    @Override
    public void saveNewDeploye(File file, String filename)
    {
        try
        {
            // 2：将File类型的文件转化成ZipInputStream流
            ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(file));
            repositoryService.createDeployment()// 创建部署对象
            .name(filename)// 添加部署名称
            .addZipInputStream(zipInputStream)//
            .deploy();// 完成部署
            zipInputStream.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /** 查询流程定义的信息，对应表（act_re_procdef） */
    @Override
    public List<ProcessDefinition> findProcessDefinitionList(QueryFilter localQueryFilter)
    {
        String companyId = "1";
        Long totalcount = (repositoryService.createProcessDefinitionQuery().count());
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKeyLike(
            "_" + companyId + "_%")// 创建流程定义查询
        .latestVersion().orderByProcessDefinitionId().desc().listPage(
            localQueryFilter.getPagingBean().getFirstResult(),
            localQueryFilter.getPagingBean().getPageSize());
        localQueryFilter.getPagingBean().setTotalItems(totalcount.intValue());

        return list;
    }

    @Override
    public List<Deployment> findDeploymentList(QueryFilter localQueryFilter)
    {
        String companyId = "1";
        Long totalcount = repositoryService.createDeploymentQuery().count();
        List<Deployment> list = repositoryService.createDeploymentQuery().processDefinitionKeyLike(
            "_" + companyId + "_%")// 创建流程定义查询
        .orderByDeploymenTime().desc().listPage(localQueryFilter.getPagingBean().getFirstResult(),
            localQueryFilter.getPagingBean().getPageSize());
        localQueryFilter.getPagingBean().setTotalItems(totalcount.intValue());
        return list;
    }

    /** 使用部署对象ID，删除流程定义 */
    @Override
    public void deleteProcessDefinitionByDeploymentId(String deploymentId)
    {
        repositoryService.deleteDeployment(deploymentId, true);
    }

    public InputStream findImageInputStream(String deploymentId, String imageName)
    {
        return repositoryService.getResourceAsStream(deploymentId, imageName);
    }

    public InputStream findXMLInputStream(String deploymentId, String XMLName)
    {
        return repositoryService.getResourceAsStream(deploymentId, XMLName);
    }

    // 查询某公司下的所有流程
    @Override
    public List<ProcessDefinition> findProcessDefinitionDistinctByCmpId(String companyId)
    {

        return repositoryService.createProcessDefinitionQuery().processDefinitionKeyLike(
            "_" + companyId + "_%").latestVersion().orderByProcessDefinitionId().asc().list();

    }

    @Override
    public ProcessDefinition findProcessDefinitionByKey(String processDefinitionKey)
    {
        return repositoryService.createProcessDefinitionQuery().processDefinitionKey(
            processDefinitionKey).latestVersion().singleResult();
    }

    /** 更新请假状态，启动流程实例，让启动的流程实例关联业务 */
    @Override
    public void saveStartProcess(String businessId, Class<?> businessType,
                                 Map<String, Object> variables)
    {
        // 3：使用当前对象获取到流程定义的key（对象的名称就是流程定义的key）
        String companyId = "1";
        String deptId = "1";
        String key = "_" + companyId + "_" + businessType.getSimpleName();
        if (variables == null)
        {
            variables = new HashMap<String, Object>();
        }
        List<WorkflowConfig> listDeptNull = workflowConfigService.findCfgProcessDeptNull(
            companyId, key);
        List<WorkflowConfig> listDept = workflowConfigService.findCfgProcessDept(companyId,
            deptId, key);
        listDeptNull.addAll(listDept);
        for (WorkflowConfig wc : listDeptNull)
        {
            // 等人员选择器做好要改成 wc.getCheckUserId()
            variables.put(wc.getVariableName(), wc.getCheckUserName());
        }
        /**
         * 5： (1)使用流程变量设置字符串（格式：LeaveBill.id的形式），通过设置，让启动的流程（流程实例）关联业务
         * (2)使用正在执行对象表中的一个字段BUSINESS_KEY（Activiti提供的一个字段），让启动的流程（流程实例）关联业务
         */
        // 格式：LeaveBill.id的形式（使用流程变量）
        String objId = key + "." + businessId;
        variables.put("objId", objId);
        // 6：使用流程定义的key，启动流程实例，同时设置流程变量，同时向正在执行的执行对象表中的字段BUSINESS_KEY添加业务数据，同时让流程关联业务
        ProcessInstance pi = runtimeService.startProcessInstanceByKey(key, objId, variables);
    }

    // 流程向前推进，返回0表示流程完成，返回1表示未完成
    public Integer processForward(String instanceId, String taskId, String message,
                                  String comment, Class<?> businessType,Map<String, Object> variables)
    {
        //先查询是不是组任务
        List <IdentityLink> list=taskService.getIdentityLinksForTask(taskId);
        if(taskService.createTaskQuery().taskId(taskId).singleResult()==null&&list.size()==0){
            return -1;
        };
        //当前登录用户的ID
        String userId="admin";
        //如果是组任务，先拾取任务
        if(list.size()>0){
            taskService.claim(taskId, userId);
        }
        /**
         * 注意：添加批注的时候，由于Activiti底层代码是使用： String userId = Authentication.getAuthenticatedUserId();
         * CommentEntity comment = new CommentEntity(); comment.setUserId(userId);
         * 所有需要从Session中获取当前登录人，作为该任务的办理人（审核人），对应act_hi_comment表中的User_ID的字段，不过不添加审核人，该字段为null
         * 所以要求，添加配置执行使用Authentication.setAuthenticatedUserId();添加当前任务的审核人
         */
        Authentication.setAuthenticatedUserId(userId);
        taskService.addComment(taskId, instanceId, comment);

        if (variables == null)
        {
            variables = new HashMap<String, Object>();
        }
        String companyId = "1";
        String deptId = "1";
        String key = "_" + companyId + "_" + businessType.getSimpleName();
        List<WorkflowConfig> listDeptNull = workflowConfigService.findCfgProcessDeptNull(
            companyId, key);
        List<WorkflowConfig> listDept = workflowConfigService.findCfgProcessDept(companyId,
            deptId, key);
        listDeptNull.addAll(listDept);
        for (WorkflowConfig wc : listDeptNull)
        {
            // 等人员选择器做好要改成 wc.getCheckUserId()
            variables.put(wc.getVariableName(), wc.getCheckUserName());
        }
        variables.put("message", message);

        // 3：使用任务ID，完成当前人的个人任务，同时流程变量
        taskService.complete(taskId, variables);
        // 4：当任务完成之后，需要指定下一个任务的办理人（使用类）-----已经开发完成

        /**
         * 5：在完成任务之后，判断流程是否结束 如果流程结束了，更新请假单表的状态从1变成2（审核中-->审核完成）
         */
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()//
        .processInstanceId(instanceId)// 使用流程实例ID查询
        .singleResult();
        // 流程结束了
        if (pi == null)
        {
            return 0;
        }
        else
        {
            return 1;
        }

    }

    // 获取个人任务列表
    @Override
    public List<Task> findUnfinishedTasksByUserId(String userId, QueryFilter localQueryFilter)
    {
        Long totalcount = taskService.createTaskQuery().taskAssignee(userId).count();
        localQueryFilter.getPagingBean().setTotalItems(totalcount.intValue());
        return taskService.createTaskQuery().taskAssignee("admin").listPage(
            localQueryFilter.getPagingBean().getFirstResult(),
            localQueryFilter.getPagingBean().getPageSize());

    }
    // 获取组任务列表
    public List<Task> findUnfinishedTasksByCandidateUser(String userId, QueryFilter localQueryFilter)
    {
        Long totalcount = taskService.createTaskQuery().taskAssignee(userId).count();
        localQueryFilter.getPagingBean().setTotalItems(totalcount.intValue());
        return taskService.createTaskQuery().taskCandidateUser("admin").listPage(
            localQueryFilter.getPagingBean().getFirstResult(),
            localQueryFilter.getPagingBean().getPageSize());

    }

    @Override
    public ProcessInstance getProcessInstanceById(String instanceId)
    {
        return runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
    }

    @Override
    public List<Comment> findComentsByInstanceId(String processInstanceId)
    {
        return taskService.getProcessInstanceComments(processInstanceId);
    }
    
    /**
     * 二：查看当前活动，获取当期活动对应的坐标x,y,width,height，将4个值存放到Map<String,Object>中
         map集合的key：表示坐标x,y,width,height
         map集合的value：表示坐标对应的值
     */
    @Override
    public Map<String, Object> findCoordingByTask(String taskId) {
        //存放坐标
        Map<String, Object> map = new HashMap<String,Object>();
        //使用任务ID，查询任务对象
        Task task = taskService.createTaskQuery()//
                    .taskId(taskId)//使用任务ID查询
                    .singleResult();
        //获取流程定义的ID
        String processDefinitionId = task.getProcessDefinitionId();
        //获取流程定义的实体对象（对应.bpmn文件中的数据）
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processDefinitionId);
        //流程实例ID
        String processInstanceId = task.getProcessInstanceId();
        //使用流程实例ID，查询正在执行的执行对象表，获取当前活动对应的流程实例对象
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()//创建流程实例查询
                    .processInstanceId(processInstanceId)//使用流程实例ID查询
                    .singleResult();
        //获取当前活动的ID
        String activityId = pi.getActivityId();
        //获取当前活动对象
        ActivityImpl activityImpl = processDefinitionEntity.findActivity(activityId);//活动ID
        //获取坐标
        map.put("x", activityImpl.getX());
        map.put("y", activityImpl.getY());
        map.put("width", activityImpl.getWidth());
        map.put("height", activityImpl.getHeight());
        return map;
    }

    /**1：获取任务ID，获取任务对象，使用任务对象获取流程定义ID，查询流程定义对象*/
    @Override
    public ProcessDefinition findProcessDefinitionByTaskId(String taskId) {
        //使用任务ID，查询任务对象
        Task task = taskService.createTaskQuery()//
                    .taskId(taskId)//使用任务ID查询
                    .singleResult();
        //获取流程定义ID
        String processDefinitionId = task.getProcessDefinitionId();
        //查询流程定义的对象
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()//创建流程定义查询对象，对应表act_re_procdef 
                    .processDefinitionId(processDefinitionId)//使用流程定义ID查询
                    .singleResult();
        return pd;
    }

    @Override
    public String findInstanceIdByBusinessId(String businessId,String className)
    {
        String companyId = "1";
        String businessKey="_"+companyId+"_"+className+"."+businessId;
        HistoricProcessInstance hp=historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
        if(hp!=null){
            return hp.getId();
        }
        return null;
    }

}
